const idcardGenerator = require('./idcard_generator');
const fsWrite = require('fs-writefile-promise');
const fs = require('fs/promises')
const process = require('process')
var randomstring = require("randomstring");
var randchinese = require("randchinese");

const ramdomConfig = (avatar) => {
  return {
    name: randchinese(Math.floor(Math.random() * 6 + 1)),
    sex: Math.random() > 0.5 ? '女' : '男',
    nation: randchinese(Math.floor(Math.random() * 5 + 1)),
    year: Math.floor(Math.random() * 2018 + 1) + '',
    mon: Math.floor(Math.random() * 11 + 1) + '',
    day: Math.floor(Math.random() * 29 + 1) + '',
    // org: '喵喵县公安局',
    // validTerm: '2014.02.31-2019.02.31',
    addr: randchinese(Math.floor(Math.random() * 10 + 15)),
    idn: randomstring.generate({
      charset: 'numeric',
      length: 18,
    }),
    avatar: avatar || './images/avatar.png'
  }
}

const images_num_train = 1;
const images_num_test = 1;
function genConfig(avatar) {
  let config = ramdomConfig(avatar);
  Object.setPrototypeOf(config, {
    resizeinfo: {
      left: 120,
      top: 0,
      width: 950,
      height: 950
    }
  })
  return config;
}
async function genSingleData(i, avatars, options) {
  const config = genConfig(avatars[i]);
  try {
    const [img, size] = await idcardGenerator(config)
    const path = `${options.output || './idgen'}/${i}.png`
    await fsWrite(path, img);
    resolved++;
    return {
      type: options.type,
      path,
      size
    }
  } catch(e) {
    console.error(e);
    rejected++;
  }
  return null
}
let resolved = 0, rejected = 0;
const batchSize = 1;
async function genSomeTypeData(avatars, options) {
  let batch = Math.ceil(options.num/batchSize);
  let promises = [], finished = 0;
  for(let i=0; i<batch; i++) {
    let size = batchSize * (i+1) <= options.num ? batchSize: options.num % batchSize ;
    try {
      const reslist = await Promise.all(Array.from({ length: size  }).map((_, i) => {
        return genSingleData(finished + i, avatars, options);
      }));
      finished += size;
      console.log(`${options.type === 'train' ? '🛴 train ' : '🚲 test' }  percent : ` + Math.floor(finished*100/options.num) + '%');
      promises = promises.concat(reslist);
    } catch(e) {
      console.error(e);
    }
  }
  return promises;
}

async function main(options = {}) {
  const avatorPath = options.avatar || './images';
  const dir = await fs.opendir(avatorPath);
  const avatars = [];
  for await (const dirent of dir) {
    if (dirent.name.endsWith('png')) {
      avatars.push(avatorPath + '/' + dirent.name)
    }
    if (avatars.length > (options.train_num || 0 + options.test_num || 0)) {
      break;
    }
  }
  console.log('☀ avator load success!!');
  const trainNum = options.train_num || images_num_train;
  const testNum = options.test_num || images_num_test;
  const promises = ['train', 'test'].map((type) => {
    const isTrain = type === 'train';
    return genSomeTypeData(avatars, {
      type,
      output: isTrain ? options.train_output : options.test_output,
      num: isTrain ? trainNum :  testNum
    })
  });
  let sum = trainNum + testNum;

  // @ts-ignore
  const annotation = await Promise.allSettled(promises);
  const timer = setInterval(() => {
    console.log(`resolved: ${resolved}, rejected: ${rejected}, percent: ${Math.floor((resolved + rejected) * 100 / sum)}%`)
  }, 1000);
  clearInterval(timer);
  const trainAnnotation = annotation[0]
  const testAnnotation = annotation[1]
  await writeAnnotation(trainAnnotation.value, './train_annotation.txt');
  await writeAnnotation(testAnnotation.value, './test_annotation.txt');
  console.log(`resolved: ${resolved}, rejected: ${rejected}, percent: ${Math.floor((resolved + rejected) * 100 / sum)}%`)
}

async function writeAnnotation(annotation, path) {
  let str = '';
  annotation.forEach(item => {
    let formated = item.size.map((item) => {
      return [item[1], item[2], item[1] + item[3],  item[2] + item[4] , item[0]]
    });
    const imgInfo = [item.path, ...formated.map(item => item.map((s) => Math.round(s)).join(','))]
    str += imgInfo.join(' ') + '\n'
  });
  if (str) {
    await fs.writeFile(path, str)
    console.log(`write to ${path}`);
    return;
  }
}

exports.main = main;